/*
 * Part of knowledge engineering (ke) course work, 2010/11
 */
package se.bth.ke.firstfriend.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.solr.analysis.LowerCaseFilterFactory;
import org.apache.solr.analysis.SnowballPorterFilterFactory;
import org.apache.solr.analysis.StandardTokenizerFactory;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.AnalyzerDef;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Parameter;
import org.hibernate.search.annotations.TokenFilterDef;
import org.hibernate.search.annotations.TokenizerDef;
import se.bth.ke.firstfriend.model.util.Slug;

/**
 *
 * @author nico.rehwaldt, markus
 */
@Entity
@Indexed
@AnalyzerDef(
    name = "customanalyzer",
    tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
    filters = {
        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
        @TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = {
            @Parameter(name = "language", value = "English")
        })
})
@Analyzer(definition="customanalyzer")
public class Article implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Field(index=Index.TOKENIZED)
    private String title;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;

    @Temporal(TemporalType.TIMESTAMP)
    private Date editedAt;
    
    @Field(index=Index.TOKENIZED)
    @Column(columnDefinition="LONGTEXT NOT NULL")
    private String content;

    @IndexedEmbedded
    @OneToMany(cascade=CascadeType.ALL, mappedBy="article")
    private List<Comment> comments;

    @IndexedEmbedded
    @ManyToMany
    @JoinTable(name="article_topic",
        joinColumns={@JoinColumn(name="article_id")},
        inverseJoinColumns={@JoinColumn(name="topic_id")}
    )
    private List<Topic> topics;

    @OneToMany(mappedBy="article")
    private List<Rating> ratings = new ArrayList<Rating>();
    
    private String slug;
    private double rating = -1;    
    private double relevance = -1;
    /**
     * No-Args constructor for persistence layer (is required)
     */
    public Article() {}

    public Article(String title, String content) {
        this.title = title;
        this.content = content;

        this.createdAt = new Date();
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @return the content
     */
    public String getContent() {
        return content;
    }

    /**
     * @return the createdAt
     */
    public Date getCreatedAt() {
        return createdAt;
    }

    /**
     * @return the editedAt
     */
    public Date getEditedAt() {
        return editedAt;
    }

    /**
     * @return the rating
     */
    public double getRating() {
        return rating;
    }

    public double getRelevance() {
        return relevance;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param content the content to set
     */
    public void setContent(String content) {
        this.content = content;
    }

    /**
     * @param editedAt the editedAt to set
     */
    public void setEditedAt(Date editedAt) {
        this.editedAt = editedAt;
    }

    /**
     * @param rating the rating to set
     */
    public void setRating(double rating) {
        this.rating = rating;
    }

    public void setRelevance(double relevance) {
        this.relevance = relevance;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    public void addComment(Comment c) {
        if (this.comments == null) {
            this.comments = new ArrayList();
        }

        comments.add(c);
    }

    @Override
    public String toString() {
        return "se.bth.ke.firstfriend.model.Article[id=" + id + "]";
    }

    /**
     * @return the topics
     */
    public List<Topic> getTopics() {
        if (topics == null) {
            topics = new ArrayList();
        }

        return topics;
    }

    /**
     * @param topics the topics to set
     */
    public void setTopics(List<Topic> newTopics) {
        List<Topic> thisTopics = getTopics();

        // Remove old topic references
        thisTopics.clear();
//
//        // Wire together new topic references
//        for (Topic t: newTopics) {
//            t.getArticles().add(this);
//        }

        thisTopics.addAll(newTopics);
    }

    @PrePersist
    private void createSlug() {
        this.slug = Slug.createSlug(title);
    }

    /**
     * @return the comments
     */
    public List<Comment> getComments() {
        return comments;
    }

    /**
     * @return the slug
     */
    public String getSlug() {
        return slug;
    }

    /**
     * Return a slugged id (an id of the article with some human readable text
     * appended to it)
     *
     * @return
     */
    public String getSluggedId() {
        return id + "-" + slug;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Article)) {
            return false;
        }
        Article other = (Article) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }
}
